package chap_01_CompletableFuture.step_04_LockSupport;

import java.util.concurrent.TimeUnit;

/**
 * @Description 最原始的 wait、notify 实现阻塞、唤醒
 * @Author shihan
 * @Date 2022/10/23 10:10
 * @Version 1.0
 */
public class LockSupport_01_WaitNotify {

    /**
     * 局限性：
     * 1、wait、notify 必须要在 synchronized 代码块中；
     * 2、wait、notify 必须成对出现，并且需要注意顺序问题，如果在出现 wait 后没有 notify，线程将会一直阻塞；
     *
     * @param args
     */
    public static void main(String[] args) {
        Demo lock = new Demo();
        // 案例：实现两个线程之间的交替输出打印
        new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                if (i == 4) {
                    lock.printA(true);
                } else {
                    lock.printA(false);

                }
            }
        }, "t1").start();

        // 延迟 100 毫秒，保证第一个先执行（思考：如果不 sleep 有什么办法能保证第一个线程先执行吗？待后面学习更多内容后，再来回答这个问题！）
        try {
            TimeUnit.MILLISECONDS.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                if (i == 4) {
                    lock.printB(true);
                } else {
                    lock.printB(false);

                }
            }
        }, "t2").start();
    }

}

class Demo {

    public static final String[] zimu = new String[]{"a", "b", "c", "d", "e"};
    public static final String[] shuzi = new String[]{"1", "2", "3", "4", "5"};
    private int z = 0;
    private int s = 0;

    /**
     * 为什么要加 isEnd 呢，是因为最后一次的时候，其实是不需要 wait 自己的，主要是这个原因
     *
     * @param isEnd
     */
    public synchronized void printA(boolean isEnd) {
        System.out.println(Thread.currentThread().getName() + ":" + zimu[z++]);
        notifyAll();
        try {
            if (!isEnd) {
                wait();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public synchronized void printB(boolean isEnd) {
        System.out.println(Thread.currentThread().getName() + ":" + shuzi[s++]);
        notifyAll();
        try {
            if (!isEnd) {
                wait();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
